//
//  JCObjectSelector.m
//  JCSDK
//
//  Created by master on 16/3/22.
//  Copyright © 2016年 AdMaster. All rights reserved.
//

#import "JCObjectSelector.h"
#import "JCObjectFilter.h"
@interface JCObjectSelector ()
{
    NSCharacterSet *_classAndPropertyChars;
    NSCharacterSet *_separatorChars;
    NSCharacterSet *_predicateStartChar;
    NSCharacterSet *_predicateEndChar;
    NSCharacterSet *_flagStartChar;
    NSCharacterSet *_flagEndChar;
}

@property (nonatomic, strong) NSScanner *scanner;
@property (nonatomic, strong) NSArray *filters;

@end

@implementation JCObjectSelector

- (instancetype)initWithString:(NSString *)string {
    if(self = [super init]) {
        _string = string;
        _scanner = [NSScanner scannerWithString:string];
        [_scanner setCharactersToBeSkipped:nil];
        _separatorChars = [NSCharacterSet characterSetWithCharactersInString:@"/"];
        _predicateStartChar = [NSCharacterSet characterSetWithCharactersInString:@"["];
        _predicateEndChar = [NSCharacterSet characterSetWithCharactersInString:@"]"];
        _classAndPropertyChars = [NSCharacterSet characterSetWithCharactersInString:@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.*"];
        _flagStartChar = [NSCharacterSet characterSetWithCharactersInString:@"("];
        _flagEndChar = [NSCharacterSet characterSetWithCharactersInString:@")"];
        
        NSMutableArray *filters = [NSMutableArray array];
        JCObjectFilter *filter;
        while((filter = [self nextFilter])) {
            [filters addObject:filter];
        }
        self.filters = [filters copy];
    }
    return self;
}
/**
 *  NSScanner 类遍历所有filter 每次遍历一个
 *
 *  @return filter 条件
 */
- (JCObjectFilter *)nextFilter {
    JCObjectFilter *filter;
    if([_scanner scanCharactersFromSet:_separatorChars intoString:nil]) {
        NSString *name = nil;
        filter = [[JCObjectFilter alloc] init];
        if([_scanner scanCharactersFromSet:_classAndPropertyChars intoString:&name]) {
            filter.name = name;
        } else {
            filter.name = @"*";
        }
        
        if([_scanner scanCharactersFromSet:_flagStartChar intoString:nil]) {
            NSString *flags = nil;
            [_scanner scanUpToCharactersFromSet:_flagEndChar intoString:&flags];
            for(NSString *flag in [flags componentsSeparatedByString:@"|"]) {
                if([flag isEqualToString:@"unique"]) {
                    filter.unique = YES;
                }
            }
        }
        
        if([_scanner scanCharactersFromSet:_predicateStartChar intoString:nil]) {
            NSString *predicateFormate;
            NSInteger index = 0;
            if ([_scanner scanInteger:&index] && [_scanner scanCharactersFromSet:_predicateEndChar intoString:nil]) {
                filter.index = @((NSInteger)index);
            } else {
                [_scanner scanUpToCharactersFromSet:_predicateEndChar intoString:&predicateFormate];
                @try {
                    NSPredicate *parsedPredicate = [NSPredicate predicateWithFormat:predicateFormate];
                    filter.predicate = [NSPredicate predicateWithBlock:^BOOL(id  _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
                        @try {
                            return [parsedPredicate evaluateWithObject:evaluatedObject substitutionVariables:bindings];
                        }
                        @catch (NSException *exception) {
                            return false;
                        }
                        
                    }];
                }
                @catch (NSException *exception) {
                    filter.predicate = [NSPredicate predicateWithValue:NO];
                }
             
                [_scanner scanCharactersFromSet:_predicateEndChar intoString:nil];
               
            }
            
        }
    }
    
    return filter;
}


#pragma mark 从父节点查找子节点
/**
 *  精确定位 叶子节点
 *
 *  @param root 父节点
 *
 *  @return <#return value description#>
 */
- (NSArray *)selectFromRoot:(id)root {
    return [self selectFromRoot:root evaluatingFinalPredicate:YES];
}

/**
 *  模糊查询 叶子节点
 *
 *  @param root 父节点
 *
 *  @return <#return value description#>
 */
- (NSArray *)fuzzySelectFromRoot:(id)root {
    return [self selectFromRoot:root evaluatingFinalPredicate:NO];
}

/**
 *  从父节点查找符合条件的object
 *
 *  @param root           父节点
 *  @param finalPredicate 是否使用正则匹配  适用模糊查询与准确定位最后叶子节点
 *
 *  @return <#return value description#>
 */
- (NSArray *)selectFromRoot:(id)root evaluatingFinalPredicate:(BOOL)finalPredicate {
    NSArray *views = @[];
    if (root) {
        views = @[root];
        
        for (NSUInteger i = 0, n = [_filters count]; i < n; i++) {
            JCObjectFilter *filter = _filters[i];
            filter.nameOnly = (i == n-1 && !finalPredicate);
            views = [filter apply:views];
            if ([views count] == 0) {
                break;
            }
        }
    }
    return views;
}


#pragma mark 从子节点判断子节点的合法性

/**
 *  精确判断叶子节点的合法性
 *
 *  @param leaf 当前需要判断的叶view
 *  @param root 父节点view
 *
 *  @return
 */
- (BOOL)isLeafSelected:(id)leaf fromRoot:(id)root {
    return [self isLeafSelected:leaf fromRoot:root evaluatingFinalPredicate:YES];
}

/**
 *  模糊判断叶子节点的合法性
 *
 *  @param leaf 当前需要判断的叶view
 *  @param root 父节点view
 *
 *  @return
 */
- (BOOL)fuzzyIsLeafSelected:(id)leaf fromRoot:(id)root {
    return [self isLeafSelected:leaf fromRoot:root evaluatingFinalPredicate:NO];
}

- (BOOL)isLeafSelected:(id)leaf fromRoot:(id)root evaluatingFinalPredicate:(BOOL)finalPredicate
{
    BOOL isSelected = YES;
    NSArray *views = @[leaf];
    NSUInteger n = [_filters count], i = n;
    while(i--) {
        JCObjectFilter *filter = _filters[i];
        filter.nameOnly = (i == n-1 && !finalPredicate);
        if (![filter appliesToAny:views]) {
            isSelected = NO;
            break;
        }
        views = [filter applyReverse:views];
        if ([views count] == 0) {
            break;
        }
    }
    return isSelected && [views indexOfObject:root] != NSNotFound;
}


@end
